﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Security;
using System.Security.Permissions;
using log4net;
using System.Data;
using System.Threading;

namespace TsCore
{
    
    public class TsSystem
    {
        
        private static TsSystem _instance = null;
        
        protected TsSystem()
        {
            //CleanUpMembershipUsers();// --Para hacer limpieza en pruebas
            IntializeDefaultUser();
        }

        public static TsSystem Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new TsSystem();
                    log4net.Config.XmlConfigurator.Configure();
                }
                return _instance;
            }
        }

        #region User management
        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public void CreateNewUser(string Name, String Surname, String UserName, String Password, String Email, string[] TsRoles)
        {
            try
            {
                UserHandler uh = UserHandler.Instance;
                uh.CreateNewUser(Name, Surname, UserName, Password, Email, TsRoles);
                LogManager.GetLogger(Membership.GetUser().UserName).Info("Se ha creado un nuevo usuario " + UserName);
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al crear un nuevo usuario: " + UserName, ex);
            }
        }
                
        // Esta operación puede hacerce pública y permitir el ABM de Roles
        private void CreateRol(String newRoleName)
        {
            if (!Roles.RoleExists(newRoleName))
            {
                Roles.CreateRole(newRoleName);
                if (Membership.GetUser() != null)
                {
                    LogManager.GetLogger(Membership.GetUser().UserName).Info("Se ha creado un nuevo rol " + newRoleName);
                }
                else
                {
                    LogManager.GetLogger("Anonimo").Info("Se ha creado un nuevo rol " + newRoleName);
                }
            }
        }

        public void IntializeDefaultUser()
        {
            if (Membership.GetUser("admin") == null)
            {
                this.CreateRol("Administrador");
                this.CreateRol("Seguidor");
                this.CreateRol("Visitante");
                UserHandler.Instance.CreateNewUser("Administrador", "", "admin", "admin", "admin@TeamSport.com", new string[] { "Administrador", "Seguidor", "Visitante" });
            }
        }

        private void CleanUpMembershipUsers()
        {
            var users = Membership.GetAllUsers();
            foreach (MembershipUser u in users)
            {
                Membership.DeleteUser(u.UserName, true);
            }
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public string[] GetRoles()
        {
            return UserHandler.Instance.GetRoles();
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public string[] GetUserRoles(String UserName)
        {
            return UserHandler.Instance.GetUserRoles(UserName);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public MembershipUserCollection GetAllUsers()
        {
            return UserHandler.Instance.GetAllUsers();
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public TsUser GetUser(String UserName)
        {
            try
            {
                return UserHandler.Instance.GetUser(UserName);
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al crear un nuevo usuario: " + UserName, ex);
                return null;
            }
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public void UpdateUser(TsUser UpdatedUser, List<String> RoleList)
        {
            UserHandler.Instance.UpdateUser(UpdatedUser,RoleList);
        }
        
        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public void RemoveUser(String UserName)
        {
            string[] userRoles = GetUserRoles(UserName);
            if (userRoles.Length > 0)
                Roles.RemoveUserFromRoles(UserName, userRoles);
            Membership.DeleteUser(UserName);
            UserHandler.Instance.RemoveUser(UserName);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        public void FollowTeam(String UserName, Team TeamToFollow)
        {
            UserHandler.Instance.FollowTeam(UserName, TeamToFollow);
        }
        
        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        public TsUser GetFullUserData(String UserName)
        {
            return UserHandler.Instance.GetFullUserData(UserName);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        public List<Comment> GetCommentsFromTeam(Team Team)
        {
            return SportHandler.Instance.GetCommentsFromTeam(Team);
        }

        public List<AuditLogEntity> GetUserLogons(DateTime fromDate, DateTime toDate)
        {
            List<AuditLogEntity> retList = new List<AuditLogEntity>();
            try
            {
                using (TsContext ctx = new TsContext())
                {
                    retList = (from u in ctx.Logs
                               where u.Date >= fromDate && u.Date <= toDate && u.Level == "INFO"
                               select u).ToList<AuditLogEntity>();
                }
                
            }
            catch (Exception ex)
            {
                 LogManager.GetLogger(Membership.GetUser().UserName).Error("Error al obtener los logons", ex);
            }
            return retList;
        }
        
        #endregion

        #region Sports & Team management

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Visitante")]
        public List<Sport> GetAllSports()
        {
            return SportHandler.Instance.GetAllSports();
        }
        
        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public void CreateNewSport(String SportName)
        {
            SportHandler.Instance.CreateNewSport(SportName);
        }        

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public void UpdateSport(Sport UpdatedSport)
        {
            SportHandler.Instance.UpdateSport(UpdatedSport);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Visitante")]
        public Sport GetSport(String SportName)
        {
            return SportHandler.Instance.GetSport(SportName);
        }
        
        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Visitante")]
        public Sport GetSport(int SportId)
        {
            return SportHandler.Instance.GetSport(SportId);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Visitante")]
        public Sport GetSportWithTeams(int SportId)
        {
            return SportHandler.Instance.GetSportWithTeams(SportId);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Visitante")]
        public List<Team> GetAllTeams()
        {
            List<Team> toReturn = new List<Team>();
            foreach (Team team in SportHandler.Instance.GetAllTeams())
            {
                if (!(team.IsDummyTeam))
                {
                    toReturn.Add(team);
                }
            }
            return toReturn;
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Visitante")]
        public List<Team> GetAllTeamsWithFollowers()
        {
            return SportHandler.Instance.GetAllTeamsWithFollowers();
        }
        
        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public void CreateNewTeam(String TeamName, String ImageUrl, List<Comment> CommentList, Sport TeamSport)
        {
            SportHandler.Instance.CreateNewTeam(TeamName, ImageUrl, CommentList, TeamSport);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Visitante")]
        public Team GetTeam(int TeamId)
        {
            return SportHandler.Instance.GetTeam(TeamId);
        }
        
        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Visitante")]
        public Team GetTeamWithoutIncludes(int TeamId)
        {
            return SportHandler.Instance.GetTeamWithoutIncludes(TeamId);
        }
        
        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public void UpdateTeam(Team UpdatedTeam)
        {
            foreach (Comment newComment in UpdatedTeam.Comments)
            {
                if (newComment.CommentId == 0)
                {
                    List<TsUser> usersToNotify = UserHandler.Instance.GetUsersForTeam(UpdatedTeam);

                    foreach (TsUser userToNotify in usersToNotify)
                    {
                        Thread t = (new Thread(() => Notifications.Instance.Alert.SendAlert(newComment, userToNotify)));
                        t.Start();
                        Thread.Sleep(50);
                    }   
                }
            }
            SportHandler.Instance.UpdateTeam(UpdatedTeam);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Visitante")]
        public List<Team> GetAllTeamsSortedByName(bool DescendingOrder)
        {
            List<Team> retList = (from t in SportHandler.Instance.GetAllTeamsSortedByName(DescendingOrder)
                                  where t.IsDummyTeam == false
                                  select t).ToList<Team>();

            return retList;
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Visitante")]
        public List<Team> GetAllTeamsFilteredByName(String NamePart)
        {
            return SportHandler.Instance.GetAllTeamsFilteredByName(NamePart);
        }
        
        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Visitante")]
        public List<Match> GetAllMatches()
        {
            return MatchHandler.Instance.GetAllMatches();
        }
        
        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Visitante")]
        public Match GetMatch(Int32 MatchKey)
        {
            return MatchHandler.Instance.GetMatch(MatchKey);
        }
        
        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Visitante")]
        public List<Match> GetMatchesForSport(Sport sport)
        {
            List<Match> toReturn = new List<Match>();

            foreach (Team auxTeam in sport.Teams)
            {
                foreach (Match auxMatch in MatchHandler.Instance.GetMatchesForTeam(auxTeam))
                {
                    if (!(toReturn.Contains(auxMatch)))
                    {
                        toReturn.Add(auxMatch);
                    }
                }
            }
            return toReturn;
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Visitante")]
        public List<Team> GetTeamsForSport(Int32 sport)
        {
            List<Team> toReturn = new List<Team>();
            List<Team> teams = SportHandler.Instance.GetAllTeams();

            foreach (Team auxTeam in teams)
            {
                if (GetTeam(auxTeam.TeamId).Sport.SportId == sport)
                    toReturn.Add(auxTeam);
            }
            return toReturn;
        }

        public List<Team> GetFavoriteTeamsForUser(TsUser user)
        {
            return UserHandler.Instance.GetFavoriteTeamsForUser(user);
        }

        #endregion

        #region Match management

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public List<Match> GetMatchesForTeam(Team team)
        {
            return MatchHandler.Instance.GetMatchesForTeam(team);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public void CreateNewMatch(DateTime Date, Team HomeTeam, Team VisitorTeam)
        {
            MatchHandler.Instance.CreateNewMatch(Date, HomeTeam, VisitorTeam);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Visitante")]
        public List<Match> GetAllMatchesWithTeams()
        {
            return MatchHandler.Instance.GetAllMatchesWithTeams();
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public void AutoGenerateMatches(DateTime fromDate, Fixture fixture, List<Team> teams)
        {
            MatchHandler.Instance.AutoGenerateMatches(fromDate, fixture, teams);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        public DataTable GetCalendarForDate(int Month, int Year)
        {
            List<Sport> SportList = SportHandler.Instance.GetAllSports();
            return MatchHandler.Instance.GetCalendarForDate(Month, Year, SportList);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        public List<Match> GetMatchesForDateAndSport(DateTime MatchDate, int SportId)
        {
            return MatchHandler.Instance.GetMatchesForDateAndSport(MatchDate, SportId);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        public List<Position> GetPositionTable(Sport sport)
        {
            return MatchHandler.Instance.GetPositionTable(sport);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public void RemoveTeam(Team team)
        {
            SportHandler.Instance.RemoveTeam(team);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public void RemoveSport(Sport sport)
        {
            SportHandler.Instance.RemoveSport(sport);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        [PrincipalPermission(SecurityAction.Demand, Role = "Seguidor")]
        public void updateMatch(Match updatedMatch)
        {
            MatchHandler.Instance.UpdateMatch(updatedMatch);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public void RemoveMatch(Match match)
        {
            MatchHandler.Instance.RemoveMatch(match);
        }

        [PrincipalPermission(SecurityAction.Demand, Role = "Administrador")]
        public List<Fixture> GetAvailableFixtureGenerators()
        {
            return MatchHandler.Instance.GetFixtureGenerators();
        }

        public Fixture GetFixtureById(int FixtureID)
        {
            Fixture retFixture = (from f in MatchHandler.Instance.GetFixtureGenerators()
                                  where f.FixtureId == FixtureID
                                  select f).SingleOrDefault();
            return retFixture;
        }

        #endregion

        public void LogSuccesLogin(string UserName)
        {
            LogManager.GetLogger(UserName).Info("Inicio de sesión");
        }

        public void LogFailedLogin(string UserName)
        {
            LogManager.GetLogger("Anónimo").Info(UserName + " a fallado al iniciar sesión");
        }       
    }
}
